//
//  Sprite.cpp
//  Prism
//
//  Created by Bas du Pre on 20-05-11.
//  Copyright 2011 UU. All rights reserved.
//

#include <cmath>
#include "graphics/Sprite.h"

using namespace Prism;
using namespace Prism::Graphics;

Sprite::Sprite() :
_animation(0),
myTexture(false)
{
    _textureFrame = new TextureFrame();
    native_init();
    init();
}

Sprite::Sprite(Texture *texture) :
_animation(0)
{
    native_init();
    _textureFrame = new TextureFrame();
    _textureFrame->setTexture(texture);
    myTexture = false;
    native_loadSprite();
    init();
}

Sprite::Sprite(File &file) :
_animation(0) {
    native_init();
    _textureFrame = new TextureFrame();
    _textureFrame->setTexture(new Texture(&file));
    myTexture = true;
    native_loadSprite();
    init();
}

Sprite::Sprite(String filename) :
_animation(0) {
    native_init();
    _textureFrame = new TextureFrame();
    _textureFrame->setTexture(new Texture(filename));
    myTexture = true;
    native_loadSprite();
    init();
}

Sprite::Sprite(TextureFrame *textureFrame) :
_animation(0) {
    native_init();
    _textureFrame = new TextureFrame();
    _textureFrame->setTexture(textureFrame->texture());
    _textureFrame->setRect(textureFrame->rect());
    myTexture = false;
    native_loadSprite();
    init();
}

Sprite::Sprite(TextureFrame &textureFrame) :
_animation(0) {
    native_init();
    _textureFrame = new TextureFrame();
    _textureFrame->setTexture(textureFrame.texture());
    _textureFrame->setRect(textureFrame.rect());
    myTexture = false;
    native_loadSprite();
    init();
}

Sprite::Sprite(Animation *animation) {
    native_init();
    _textureFrame = new TextureFrame();
    _textureFrame->setTexture(animation->getFrame(0)->texture());
    _textureFrame->setRect(animation->getFrame(0)->rect());
    myTexture = false;
    native_loadSprite();
    setAnimation(animation);
    init();
}

void Sprite::init() {
    _dt = 0;
	_animationFrame = 0;
    onUpdate += delegate(this, &Sprite::onUpdateAnimate);
    _textureFrame->onChanged += delegate(this, &Sprite::onTextureFrameChanged);
}

///\todo coverspoints
/// http://www.cocos2d-iphone.org/forum/topic/3737

Sprite::~Sprite() {
    //todo: native_unloadSprite();
    if (myTexture)
        delete _textureFrame->texture();
    delete _textureFrame;
}

Prism::Rect Sprite::boundingBox() {
    return native_boundingBox();
}

Prism::String Sprite::toString() {
    //return "[Sprite]";
    return String::fromFormat("[Sprite texture=%@]", _textureFrame->texture(), 0);
}

Texture *Sprite::texture() {
    return _textureFrame->texture();
}

void Sprite::setTexture(Texture* texture) {
    _textureFrame->setTexture(texture);
}

TextureFrame* Sprite::textureFrame() {
    return _textureFrame;
}

void Sprite::setTextureFrame(TextureFrame &textureFrame) {
    _textureFrame->setTexture(textureFrame.texture());
    _textureFrame->setRect(textureFrame.rect());
}

Prism::Rect Sprite::rect() {
    return _textureFrame->rect();
}

void Sprite::setRect(Rect rect) {
    _textureFrame->setRect(rect);
}

void Sprite::onTextureFrameChanged(void* sender, EventArgs* e) {
    native_updateSprite();
}

void Sprite::setAnimation(Animation *animation) {
    _animation = animation;
}

Animation *Sprite::animation() {
    return _animation;
}

void Sprite::removeAnimation() {
    setAnimation(0);
}

void Sprite::onUpdateAnimate(void* sender, UpdateEventArgs* e) {    
    Animation *a = animation();
    if (a == 0) return;
            
    _dt += e->delta;
    if (_dt >= a->delay()) {
        PInt frames = floor(_dt / a->delay());
        _dt -= frames * a->delay();
        
        _animationFrame = (_animationFrame + frames) % a->length();
        
        setTextureFrame(*a->getFrame(_animationFrame));
    }
}

